import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'dart:ui';

import 'package:animation_effect_demo/src/effects/base/base_effect.dart';
import 'package:flutter/material.dart' hide Image;

import '../../utils/download_util.dart';
import '../../utils/image_util.dart';
import 'image_operation.dart';


class ImageDataInfo {
  Uint8List data;
  int width;
  int height;

  ImageDataInfo(this.data, this.width, this.height);
}
abstract class ImageAnimationEffect implements BaseEffect {

  Future<Image?> _getImageData(
      {required String imageUrl, int? width, int? height}) async {
    if (imageUrl.startsWith('http')) {
      var file = await DownloadUtil.downloadFile(imageUrl, fromCache: true);

      if (file == null) {
        return null;
      }
      final bytes = await file.readAsBytes();
      final codec = await instantiateImageCodec(
        bytes,
        targetHeight: height,
        targetWidth: width,
      );

      return (await codec.getNextFrame()).image;
    } else if(imageUrl.startsWith('assets/') || imageUrl.startsWith('packages/') ){
      return await ImageUtil.getUIImage(imageUrl, width: width, height: height);
    } else {
      var file = File(imageUrl);
      final bytes = await file.readAsBytes();
      final codec = await instantiateImageCodec(
        bytes,
        targetHeight: height,
        targetWidth: width,
      );

      return (await codec.getNextFrame()).image;
    }
  }

  Future<List<List<Color>>> getFrameByImagePath(String imageUrl,
      {required FixType fixType,
        int? width,
        int? height,
        int? cropWidth,
        int? cropHeight}) async {
    Image? image =
    await _getImageData(imageUrl: imageUrl, width: width, height: height);
    if (image == null) {
      return [];
    }
    var byteData = await image.toByteData();

    final imageData = Uint8List.view(byteData!.buffer);
    final List<List<Color>> columnRow = [];
    int cropX;
    int cropY;

    ///FixType.none 需要左上角对齐
    if (cropWidth != null) {
      cropX = ((image.width - cropWidth) ~/ 2).abs();
    } else {
      cropX = 0;
    }

    if (cropHeight != null) {
      cropY = ((image.height - cropHeight) ~/ 2).abs();
    } else {
      cropY = 0;
    }

    int columnCount = cropWidth ?? image.width;
    int rowCount = cropHeight ?? image.height;

    if (fixType == FixType.contain) {
      for (var column = 0; column < columnCount; column++) {
        List<Color> rowData = List.filled(rowCount, Colors.black);
        if (column >= cropX && column < cropX + image.width) {
          for (var row = 0; row < rowCount; row++) {
            if (row >= cropY && row < cropY + image.height) {
              int pixelStartPosition =
                  ((row - cropY) * image.width * 4) + (column - cropX) * 4;
              int alpha = imageData[pixelStartPosition + 3];
              rowData[row - cropY] = Color.fromARGB(
                alpha,
                imageData[pixelStartPosition],
                imageData[pixelStartPosition + 1],
                imageData[pixelStartPosition + 2],
              );
            }
          }
        }
        columnRow.add(rowData);
      }
    } else if (fixType == FixType.cover) {
      for (var column = 0; column < image.width; column++) {
        if (column >= cropX && column < cropX + columnCount) {
          List<Color> rowData = List.filled(rowCount, Colors.black);
          for (var row = 0; row < image.height; row++) {
            if (row >= cropY && row < cropY + rowCount) {
              int pixelStartPosition = (row * image.width * 4) + column * 4;
              int alpha = imageData[pixelStartPosition + 3];
              rowData[row - cropY] = Color.fromARGB(
                alpha,
                imageData[pixelStartPosition],
                imageData[pixelStartPosition + 1],
                imageData[pixelStartPosition + 2],
              );
            }
          }
          columnRow.add(rowData);
        }
      }
    } else {
      for (var column = 0; column < columnCount; column++) {
        List<Color> rowData = List.filled(rowCount, Colors.black);
        if (column < image.width) {
          for (var row = 0; row < rowCount; row++) {
            if (row < image.height) {
              int pixelStartPosition = (row * image.width * 4) + column * 4;
              int alpha = imageData[pixelStartPosition + 3];
              rowData[row] = Color.fromARGB(
                alpha,
                imageData[pixelStartPosition],
                imageData[pixelStartPosition + 1],
                imageData[pixelStartPosition + 2],
              );
            }
          }
        }
        columnRow.add(rowData);
      }
    }

    return columnRow;
  }

  Future<Uint8List?> getImageDataByImagePath(String imageUrl,
      {int? width, int? height}) async {
    Image? image =
    await _getImageData(imageUrl: imageUrl, width: width, height: height);
    if (image != null) {
      final byteData = await image.toByteData();
      return Uint8List.view(byteData!.buffer);
    }
    return null;
  }

}
